package com.example.graphicslib.utils;

import java.util.Stack;
import java.util.StringTokenizer;

/**
 * Created by Tatev on 1/3/14.
 */
public class Function {

    public Function(String function) {
        this.function = function;
    }

    public double apply(long value) {
        if (function.length() > 2) {
            String modified = function.replaceAll("[$][xt]", Long.toString(value));
            //replaceWithValues(modified);
            return calculate(modified);
        }

        return value;
    }

    private double calculate(String expression) {

        String token;
        Stack<Double> values = new Stack<Double>();
        Stack<String> operators = new Stack<String>();

        expression = "(" + expression + ")";

        expression = expression.replace(" ", "");
        StringTokenizer tokenizer = new StringTokenizer(expression, "()*/+-^", true);

        while (tokenizer.hasMoreTokens()){
            token = tokenizer.nextToken();
            if (token.equals("("))  {
                operators.push(token);
            }
            double num;
            if (!isOperator(token) && !token.equals("(") && !token.equals(")") )
            {
                num = Double.parseDouble(token);
                values.push(num);


            }
            if (token.equals(")")){
                while (operators.peek().equals("(") == false){
                    String op = operators.peek();
                    operators.pop();
                    Double v1 = values.peek();
                    values.pop();
                    Double v2 = values.peek();
                    values.pop();
                    evaluate(op, v1, v2);
                    values.push(result);
                }
                operators.pop();
            }
            if (isOperator(token)){
                while (operators.isEmpty()==false && priority(operators.peek()) >= priority(token)){
                    String op = operators.peek();
                    operators.pop();
                    double v1 = values.pop();
                    double v2 =  values.pop();
                    evaluate(op, v1, v2);
                    values.push(result);
                }
                operators.push(token);
            }

        }
        result = values.peek();
        return result;
    }

    private String replaceWithValues(String expression) {
        int i = 0;
        for (; i < expression.length(); ++i) {
            while (expression.charAt(i) >= '0' && expression.charAt(i) <= '9') {
                ++i;
            }
            int k = i;
            StringBuilder str = new StringBuilder();
            while (expression.charAt(i) >= 'a' && expression.charAt(i) <= 'z') {
                str.append(expression.charAt(i));
                ++i;
            }
            if (isOperator(String.valueOf(expression.charAt(i)))) {

            }
        }
        return null;
    }

    private boolean isOperator(String token) {
        if (token.equals("+") || token.equals("-") || token.equals("*") || token.equals("/") || token.equals("^")) {
            return true;
        } else {
            return false;
        }
    }

    private int priority(String token) {
        int precedence;
        if (token.equals("(") || token.equals(")")) {
            precedence = 0;
        } else {
            if (token.equals("^")) {
                precedence = 4;
            } else {
                if (token.equals("*") || token.equals("/")) {
                    precedence = 3;
                } else {
                    if (token.equals("+") || token.equals("-")) {
                        precedence = 2;
                    } else {
                        precedence = 1;
                    }
                }
            }
        }

        return precedence;
    }

    private double evaluate(String op, double v1, double v2) {

        if (op.equals("^")) {
            result = Math.pow(v1, v2);
        }
        if (op.equals("+")) {
            result = v2 + v1;
        }
        if (op.equals("-")) {
            result = v1 - v2;
        }
        if (op.equals("*")) {
            result = v2 * v1;
        }
        if (op.equals("/")) {
            result = v1 / v2;
        }
        return result;
    }

    private String function;
    private double result;
}
